package com.common.utils.classload;

import cn.hutool.core.lang.Console;

import java.net.URL;

/**
 * @author xin.ding
 * @date 2021/5/21 10:32
 */
public class ClassLoadTest {

    public static void main(String[] args) {
        run();
    }

    private static void print() {

        // 获得根类加载器所加载的核心类库,并会看到本机安装的Java环境变量指定的jdk中提供的核心jar包路径：
        URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
        for (URL url : urls) {
            Console.log(url.toExternalForm());
        }

        // sun.misc.Launcher$AppClassLoader
        Console.log("系统类加载器:{}", ClassLoader.getSystemClassLoader());
        Console.log("Ext类加载器:{}", ClassLoader.getSystemClassLoader().getParent());
        Console.log("当前类加载器:{}", ClassLoadTest.class.getClassLoader());
        Console.log("当前类加载器的父加载器:{}", ClassLoadTest.class.getClassLoader().getParent());
        Console.log("当前类加载器的父加载器的父加载器:{}", ClassLoadTest.class.getClassLoader().getParent().getParent());
    }

    private static void run() {
        String libPath = "classloadtest/lib";
        String jarPath = "classloadtest/maven-package-1.0.jar";

        // 运行在同一进程中
        ClassLoaderUtils.runJar(jarPath, libPath, ClassLoaderUtils.ResolveType.PARENT_FIRST);
    }

}

/*

1. 根类加载器（bootstrap class loader）:它用来加载 Java 的核心类，是用原生代码来实现的，并不继承自 java.lang.ClassLoader（负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class，由C++实现，不是ClassLoader子类）
2. 扩展类加载器（extensions class loader）：它负责加载JRE的扩展目录，lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类。由Java语言实现，父类加载器为null(bootstrap)。
3. 系统类加载器（system class loader）：被称为系统（也称为应用）类加载器，它负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性，或者CLASSPATH换将变量所指定的JAR包和类路径。程序可以通过ClassLoader的静态方法getSystemClassLoader()来获取系统类加载器。
    如果没有特别指定，则用户自定义的类加载器都以此类加载器作为父加载器。由Java语言实现，父类加载器为ExtClassLoader。

类加载器加载Class大致要经过如下8个步骤：

检测此Class是否载入过，即在缓冲区中是否有此Class，如果有直接进入第8步，否则进入第2步。
如果没有父类加载器，则要么Parent是根类加载器，要么本身就是根类加载器，则跳到第4步，如果父类加载器存在，则进入第3步。
请求使用父类加载器去载入目标类，如果载入成功则跳至第8步，否则接着执行第5步。
请求使用根类加载器去载入目标类，如果载入成功则跳至第8步，否则跳至第7步。
当前类加载器尝试寻找Class文件，如果找到则执行第6步，如果找不到则执行第7步。
从文件中载入Class，成功后跳至第8步。
抛出ClassNotFountException异常。
返回对应的java.lang.Class对象。
四、类加载机制：
1.JVM的类加载机制主要有如下3种。

全盘负责：所谓全盘负责，就是当一个类加载器负责加载某个Class时，该Class所依赖和引用其他Class也将由该类加载器负责载入，除非显示使用另外一个类加载器来载入。
双亲委派：所谓的双亲委派，则是先让父类加载器试图加载该Class，只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲，就是某个特定的类加载器在接到加载类的请求时，首先将加载任务委托给父加载器，依次递归，如果父加载器可以完成类加载任务，就成功返回；只有父加载器无法完成此加载任务时，才自己去加载。
缓存机制。缓存机制将会保证所有加载过的Class都会被缓存，当程序中需要使用某个Class时，类加载器先从缓存区中搜寻该Class，只有当缓存区中不存在该Class对象时，系统才会读取该类对应的二进制数据，并将其转换成Class对象，存入缓冲区中。这就是为很么修改了Class后，必须重新启动JVM，程序所做的修改才会生效的原因。


 */
